﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol.Data;
using HK.Core.Settings;
using HK.Core.Settings.Data;
using HK.Core.Utils;
using HK.Editor.BuildSystem;
using HK.Editor.Common;
using HK.Editor.Common.Data;
using HK.Editor.Common.Protocol;
using HK.Editor.GUIEx.Styles;
using HK.Editor.GUIEx.Window;
using HK.Editor.Serializable;
using HK.Editor.Settings.Protocol;
using HK.Editor.Utils;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
using HLogger = HK.Core.Logs.Logger;
using HCompareOptions = HK.Core.Common.Protocol.Data.CompareOptions;

namespace HK.Editor.Settings
{

    /// <summary>
    /// 场景渲染设定采样一样
    /// </summary>
    public class SceneRenderSettingsSampleException : Exception
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iMessage">Message</param>
        public SceneRenderSettingsSampleException(string iMessage) : base(iMessage) {}
    }
    
    /// <summary>
    /// 场景渲染设定编辑器
    /// </summary>
    [CustomEditor(typeof(SceneRenderSettings))]
    public class SceneRenderSettingsEditor : SAssetListEditor<SceneRenderSettings, SceneRenderSettingsList, SceneRenderSettingsData>,
        ISceneRenderSettingsEditor<SceneRenderSettings, SceneRenderSettingsList, SceneRenderSettingsData>
    {

        /// <summary>
        /// 保护构造函数
        /// </summary>
        public SceneRenderSettingsEditor() : base() {}

#region Contents

        private GUIContent _whileListIconBtn;
        
        /// <summary>
        /// 按钮 - 白名单
        /// </summary>
        protected GUIContent WhileListIconBtn
        {
            get
            {
                if (null != _whileListIconBtn && null != _whileListIconBtn.image) return _whileListIconBtn;
                _whileListIconBtn = UtilsGUIEx.CreateGuiContentWithIcon(null, EditorConst.IconWhiteList);
                return _whileListIconBtn;
            }
        }
        
#endregion

#region WhileList


        private static IOWhiteList _whiteList = null;
        /// <summary>
        /// 白名单
        /// </summary>
        protected static IOWhiteList WhiteList
        {
            get
            {
                if (null != _whiteList) return _whiteList;

                var playerPrefsSaveKey = GetPlayerPrefsSaveKey<SceneRenderSettings>();
                var savedInfo = PlayerPrefs.GetString(playerPrefsSaveKey);
                if (string.IsNullOrEmpty(savedInfo)) return null;
                _whiteList = UtilsJson<IOWhiteList>.ConvertFromJsonString(savedInfo);
                return _whiteList;
            }
            private set => _whiteList = value;
        }
        
        /// <summary>
        /// 取得白名单存档信息
        /// </summary>
        /// <returns></returns>
        private IOWhiteList GetWhiteList()
        {

            var whiteList = WhiteList;
            if (null == whiteList || !whiteList.Valid)
            {
                var fileExtensions = FileExtensions.Create(new List<FileExtension>()
                    { FileExtension.Create("unity", "Unity Scenes") });
                whiteList = IOWhiteList.Create((int)IoBrowseOptions.File, "请选择一个场景文件!", 
                    (int)HCompareOptions.SceneFileOnly, fileExtensions);
                WhiteList = whiteList;
            }
            return whiteList;
        }

        /// <summary>
        /// 保存白名单
        /// </summary>
        /// <param name="iWhiteList">白名单</param>
        /// <returns>true:OK; false:NG;</returns>
        private bool SaveWhiteList(IWhiteList iWhiteList)
        {
            if (null == iWhiteList || !iWhiteList.Valid) return false;

            var flg = false;
            if (iWhiteList is IOWhiteList whiteList)
            {
                var savedInfo = UtilsJson<IOWhiteList>.ConvertToJsonString(whiteList, false);
                if (!string.IsNullOrEmpty(savedInfo))
                {
                    var playerPrefsSaveKey = GetPlayerPrefsSaveKey<SceneRenderSettings>();
                    PlayerPrefs.SetString(playerPrefsSaveKey, savedInfo);
                    flg = true;
                }
            }
            
            return flg;
        }

        /// <summary>
        /// 是否包含在白名单中
        /// </summary>
        /// <param name="iTarget">目标</param>
        /// <returns>true:包含; false:不包含;</returns>
        private bool ContainsInWhiteList(string iTarget) => _whiteList?.Contains(iTarget) ?? false;

#endregion

#region Draw

        /// <summary>
        /// 绘制Body
        /// </summary>
        /// <param name="iEvent">Event</param>
        protected override Rect DrawOptions(Event iEvent)
        {
            var optionsRect = base.DrawOptions(iEvent);

            var whileListRect = optionsRect;
            whileListRect.xMax = optionsRect.xMin - HorizontalSpacing;
            whileListRect.xMin = whileListRect.xMax - BtnWidthIconOnly;
            whileListRect = UtilsGUIEx.DrawButton(whileListRect, iEvent, WhileListIconBtn,
                () =>
                {
                    var whiteList = GetWhiteList();
                    WhiteListWindow.ShowWindow<IOWhiteList>(whiteList, SaveWhiteList);
                }, Color.clear, GuiExHelper.PreButton);
            
            return optionsRect;
        }

#endregion

#region Menu

        private static bool SampleSceneRenderSettings(bool iClear = false)
        {
            var sceneSettings = SceneRenderSettings.Instance;
            if(null == sceneSettings) return false;
            if (iClear)
            {
                sceneSettings.Clear();
            }

            var curSceneName = SceneManager.GetActiveScene().name;
            
            // 环境光设定
            var ambient = AmbientSettings.Create(RenderSettings.ambientMode, 
                RenderSettings.ambientEquatorColor, RenderSettings.ambientGroundColor,
                RenderSettings.ambientSkyColor, RenderSettings.ambientLight, RenderSettings.ambientIntensity);
                
            // 光晕设定
            var flare = FlareSettings.Create(RenderSettings.flareFadeSpeed, RenderSettings.flareStrength);
                
            // 雾效设定
            var fog = FogSettings.Create(RenderSettings.fogMode, RenderSettings.fog, RenderSettings.fogColor, 
                RenderSettings.fogDensity, RenderSettings.fogStartDistance, RenderSettings.fogEndDistance);
                
            // 反射设定
            var reflection = ReflectionSettings.Create(RenderSettings.defaultReflectionMode, RenderSettings.reflectionBounces, RenderSettings.reflectionIntensity);
                
            // 场景设定
            var settings = SceneRenderSettingsData.Create(curSceneName, ambient, flare, fog, reflection,
                RenderSettings.haloStrength, RenderSettings.subtractiveShadowColor);

            if (!sceneSettings.SaveSettings(settings))
            {
                HLogger.Error($"SampleSceneRenderSettings():场景渲染设定信息采样失败!(Scene:{curSceneName})");
                return false;
            }
            UtilsSEAssets.SetAssetDirty(sceneSettings);
            return true;
        }

        /// <summary>
        /// 采样当前场景
        /// </summary>
        [MenuItem(EditorConst.MENU_TXT_TOOL_SAMPLE_RENDER_SETTINGS, false, EditorConst.MENU_PRIORITY_SAMPLE_RENDER_SETTINGS)]
        private static void SampleCurSceneRenderSettings()
        {
            try
            {
                if (SampleSceneRenderSettings())
                {
                    UtilsSEAssets.AssetsRefresh();
                }
            }
            catch (Exception exp)
            {
                throw new SceneRenderSettingsSampleException($"场景渲染设定信息采样失败!\n  Type:{exp.GetType().Name}\n  Message:{exp.Message}\n  StackTrace:{exp.StackTrace}");
            }
        }

        /// <summary>
        /// 采样当前场景
        /// </summary>
        [MenuItem(EditorConst.MENU_TXT_TOOL_SAMPLE_ALL_RENDER_SETTINGS, false,
            EditorConst.MENU_PRIORITY_SAMPLE_ALL_RENDER_SETTINGS)]
        private static void SampleAllSceneRenderSettings()
        {
            var scenes = EditorBuildSettings.scenes;
            var length = scenes.Length;
            if(0 >= length) return;

            var curScene = SceneManager.GetActiveScene();
            
            UtilsGUIEx.DisplayProgressBar("场景渲染信息采集", "采集中...", 0.0f);
            var costTime = new Stopwatch();
            costTime.Start();

            var flg = false;
            var first = true;
            var whiteList = WhiteList;
            for (var idx = 0; idx < length; ++idx)
            {
                var scene = scenes[idx];
                if (!UtilsEditorIo.VerifyScene(scene))
                {
                    UtilsGUIEx.ClearProgressBar();
                    // 只要有一个执行成功，则刷新
                    if (flg)
                    {
                        UtilsSEAssets.AssetsRefresh();
                    }
                    throw new UnknownSceneException($"该场景已被删除或丢失，请确认EditorBuildSettings中的场景，移除无效场景信息!(Index:{idx})");
                }
                if (string.IsNullOrEmpty(scene.path)) continue;
                // 白名单校验
                if (null != whiteList)
                {
                    if(whiteList.Contains(scene.path)) continue;
                }
                
                // 打开场景
                EditorSceneManager.OpenScene(scene.path);
                if (SampleSceneRenderSettings(first))
                {
                    first = false;
                    if (!flg)
                    {
                        flg = true;
                    }
                }
                
                UtilsGUIEx.DisplayProgressBar("场景渲染信息采集", $"采集:{scene.path}", idx, length, costTime.ElapsedMilliseconds);
            }
            
            // 恢复场景
            if (UtilsEditorIo.VerifyScene(curScene))
            {
                EditorSceneManager.OpenScene(curScene.path);
            }

            // 只要有一个执行成功，则刷新
            if (flg)
            {
                UtilsSEAssets.AssetsRefresh();
            }
            
            costTime.Stop();
            UtilsGUIEx.ClearProgressBar();
            
        }

#endregion

    }
}
